#include "ourhdr.h"
#include "ext2.h"
#include "fat32.h"

void display_sector(int fd){
	int64_t offset;
	unsigned char buf[SEC_SZ];

	while(1){
		printf("sector offset: ");
		scanf("%ld", &offset);
		if(offset < 0)
			return;
		if( lseek(fd, offset * SEC_SZ, SEEK_SET) < 0){
			fprintf(stderr,"fail to lseek\n");
			exit(1);
		}
		if( read(fd, buf, SEC_SZ) < 0 ){
			fprintf(stderr, "fail to read\n");
			exit(1);
		}
		for(int i = 0; i < SEC_SZ/16; i++){
			for(int j = 0; j < 4; j++){
				for(int k = 0; k < 4; k++){
					printf("%02x ",buf[i*16+j*4+k]);
				}
				printf(" ");
			}
			for(int j = 0; j < 16; j++){
				printf("%c", buf[i*16+j]);
			}
			printf("\n");
		}
	}

}
static void display_cluster(int fd){
	int cluster_num;
	unsigned char buf[SECS_PER_CLUS][SEC_SZ];
	DBR DBR_sector;
	lseek(fd, 0, SEEK_SET);
	read(fd, &DBR_sector, sizeof(DBR));
	uint64_t data_start = DBR_sector.DBR_BPB.BPB_RsvdSecCnt + DBR_sector.DBR_BPB.BPB_NumFATs * DBR_sector.DBR_BPB.BPB_FATSz32;
	while(1){
		printf("cluster number: ");
		scanf("%d", &cluster_num);
		getchar();
		if(cluster_num < 2){
			fprintf(stderr, "uncorrect cluster number\n");
			return ;
		}
		lseek(fd, (data_start + (cluster_num - 2) * SECS_PER_CLUS) * SEC_SZ, SEEK_SET);
		for(int i = 0; i < SECS_PER_CLUS ; i++){
			read(fd, buf[i], SEC_SZ);
		}
		int index = 0;
		while(1){
			for(int i = 0; i < SEC_SZ / 16; i++){
				for(int j = 0; j < 4; j++){
					for(int k = 0; k < 4; k++){
						printf("%02x ",buf[index][i*16+j*4+k]);
					}
					printf(" ");
				}
				for(int j = 0; j < 16; j++){
					printf("%c",buf[index][i*16+j]);
				}
				printf("\n");
			}
			printf("%d\n", index);
			char input;
			printf("input q to exit, or continue: ");
			input = getchar();
			if(input == 'q') break;
			index = (index + 1) % SECS_PER_CLUS;
		}

	}
}
void display_DBR(int fd){
	DBR		DBR_sector = {0};
	lseek(fd, 0, SEEK_SET);
	if( read(fd, &DBR_sector, sizeof(DBR_sector)) < 0){
		fprintf(stderr, "fail to read\n");
		exit(1);
	}
	printf("factory code: ");
	for(int i = 0; i < 8; i++){
		printf("%c",DBR_sector.DBR_FacCode[i]);
	}
	printf("\n");
	/*
	printf("bytes per sector: %d,%x\n",DBR_sector.DBR_BPB.BPB_BytePerSec,DBR_sector.DBR_BPB.BPB_BytePerSec);
	printf("sectors per cluster: %d,%x\n",DBR_sector.DBR_BPB.BPB_SecPerClus,DBR_sector.DBR_BPB.BPB_SecPerClus);
	printf("reserved sectors count: %d,%x\n",DBR_sector.DBR_BPB.BPB_RsvdSecCnt,DBR_sector.DBR_BPB.BPB_RsvdSecCnt);
	printf("number of fats: %d,%x\n",DBR_sector.DBR_BPB.BPB_NumFATs,DBR_sector.DBR_BPB.BPB_NumFATs);
	printf("root entry count: %d,%x\n",DBR_sector.DBR_BPB.BPB_RootEntCnt,DBR_sector.DBR_BPB.BPB_RootEntCnt);
	printf("total sectors of fat16: %d,%x\n",DBR_sector.DBR_BPB.BPB_ToSec16,DBR_sector.DBR_BPB.BPB_ToSec16);
	printf("media : %d,%x\n",DBR_sector.DBR_BPB.BPB_Media,DBR_sector.DBR_BPB.BPB_Media);
	printf("fat size of fat16: %d,%x\n",DBR_sector.DBR_BPB.BPB_FATSz16,DBR_sector.DBR_BPB.BPB_FATSz16);
	*/
	disp(DBR_sector.DBR_BPB.BPB_BytsPerSec);
	disp(DBR_sector.DBR_BPB.BPB_SecPerClus);
	disp(DBR_sector.DBR_BPB.BPB_RsvdSecCnt);
	disp(DBR_sector.DBR_BPB.BPB_NumFATs);
	disp(DBR_sector.DBR_BPB.BPB_RootEntCnt);
	disp(DBR_sector.DBR_BPB.BPB_ToSec16);
	disp(DBR_sector.DBR_BPB.BPB_Media);
	disp(DBR_sector.DBR_BPB.BPB_FATSz16);
	disp(DBR_sector.DBR_BPB.BPB_SecPerTrk);
	disp(DBR_sector.DBR_BPB.BPB_NumHeads);
	disp(DBR_sector.DBR_BPB.BPB_HidSec);
	disp(DBR_sector.DBR_BPB.BPB_ToSec32);
	disp(DBR_sector.DBR_BPB.BPB_FATSz32);
	disp(DBR_sector.DBR_BPB.BPB_Flags);
	disp(DBR_sector.DBR_BPB.BPB_FSVer);
	disp(DBR_sector.DBR_BPB.BPB_RootClus);
	disp(DBR_sector.DBR_BPB.BPB_FSIfo);
	disp(DBR_sector.DBR_BPB.BPB_BkBootSec);

	disp(DBR_sector.DBR_BS.BS_DrvNum);
	disp(DBR_sector.DBR_BS.BS_BootSig);
	disp(DBR_sector.DBR_BS.BS_VolId);
	for(int i = 0; i < 11; i++){
		printf("%c",DBR_sector.DBR_BS.BS_VolSysType[i]);
	}
	printf("\n");
	for(int i = 0; i < 8; i++){
		printf("%c",DBR_sector.DBR_BS.BS_FilSysType[i]);
	}
	printf("\n");
	return ;

}
void display_FSINFO(int fd){
	DBR		DBR_sector = {0};
	lseek(fd, 0, SEEK_SET);
	if( read(fd, &DBR_sector, sizeof(DBR_sector)) < 0){
		fprintf(stderr, "fail to read");
	}
	int fsInfoSecNum = DBR_sector.DBR_BPB.BPB_FSIfo;
	lseek( fd, fsInfoSecNum*512,SEEK_SET);
	FSINFO FSINFO_sector = {0};
	if( read(fd, &FSINFO_sector, sizeof(FSINFO_sector)) < 0){
		fprintf(stderr, "fail to read");
	}
	disp(FSINFO_sector.FSINFO_Sym);
	disp(FSINFO_sector.FSINFO_Used);
	disp(FSINFO_sector.FSINFO_LastClus);
	disp(FSINFO_sector.FSINFO_SrchEnt);
	disp16(FSINFO_sector.FSINFO_Sym);
	disp16(FSINFO_sector.FSINFO_Used);
	disp16(FSINFO_sector.FSINFO_LastClus);
	disp16(FSINFO_sector.FSINFO_SrchEnt);
	return;

}


static void show_menu(){
	printf("-1.exit\n");
	printf("0. show sector\n");
	printf("1. show DBR fields\n");
	printf("2. show fs information\n");
	printf("3. show cluster\n");
	printf("please select: ");
}

int main(int argc, char**argv){
	if(argc!=2){
		fprintf(stderr,"Usage: fat32tools device\n");
		exit(1);
	}
	int fd;
	if( (fd = open(argv[1], O_RDWR)) < 0 ){
		fprintf(stderr, "fail to open device: %s\n", argv[1]);
		exit(1);
	}
	int select;
	while(1){
		show_menu();
		scanf("%d", &select);
		switch(select){
			case 0: display_sector(fd); break;
			case 1: display_DBR(fd); break;
			case 2: display_FSINFO(fd); break;
			case 3: display_cluster(fd); break;
			case -1: return 0;
			default: fprintf(stderr, "unknown option\n");
		}
	}
	return 0;
}


